#!/usr/bin/env python
import sys, socket, time, threading
import struct
import selectors
sel = selectors.DefaultSelector()




class Frpc():
    def __init__(self, serverhost,serverport, targethost,targetport):
        self.targethost=targethost
        self.targetport=targetport
        self.server_fd = socket.create_connection((serverhost,serverport))
        self.server_fd.setblocking(False)
        sel.register(self.server_fd,selectors.EVENT_READ,self.handle_server_data)

        # fdno 转换字典
        self.fd2socket = dict()
        self.socket2fd = dict()

    def handle_server_data(self,server_fd, mask):
        # print('接收到数据')
        while server_fd:
            try:
                data = server_fd.recv(1024)  # Should be ready
                if data:
                    fdno = struct.unpack('i', data[0:4])[0]  # 提取出客户端fd
                    print(data)  # 序列化比较耗时间
                    # if not data: break
                    if self.fd2socket.get(fdno) is None:
                        client_fd = socket.create_connection((self.targethost, self.targetport))
                        client_fd.setblocking(False)
                        self.fd2socket[fdno] = client_fd.fileno()
                        sel.register(client_fd, selectors.EVENT_READ, self.sendDataToFrps)
                    else:
                        client_fd = socket.socket(fileno=self.fd2socket.get(fdno))
                        print(client_fd)
                    self.socket2fd[client_fd.fileno()] = fdno  # 构建另一个映射字典 以便返回时用
                    client_fd.send(data[4:])  # 发送真实数据
                else:
                    break
            except IOError as err:  # 非阻塞模式下调用 阻塞操作recv 如果没有数据会抛出异常
                # sel.unregister(conn)
                # conn.close()
                pass
                break

    def sendDataToFrps(self,conn, mask):
        while self.server_fd and conn:
            try:
                data = conn.recv(1020)  # Should be ready
                if data:
                    fd = self.socket2fd.get(conn.fileno())
                    data = struct.pack('i', fd) + data  # 将fd编码并发送到frps
                    print('conn ', conn, 'send data to frps...')
                    self.server_fd.send(data)
                else:
                    # print('closing', conn)
                    break
            except IOError as err:  # 非阻塞模式下调用 阻塞操作recv 如果没有数据会抛出异常
                # sel.unregister(conn)
                # conn.close()
                pass
                break

    def run(self):
        while True:
            events = sel.select()
            for key, mask in events:
                callback = key.data
                callback(key.fileobj, mask)
        print("frpc started!")


if __name__ == '__main__':
    print('Starting frpc')
    # try:
    #     port = int(sys.argv[1])
    #     targethost = int(sys.argv[2])
    #     try:
    #         targetport = int(sys.argv[3])
    #     except IndexError:
    #         targetport = port
    # except (ValueError, IndexError):
    #     print('Usage: %s port targethost [targetport]' % sys.argv[0])
    #     sys.exit(1)

    # sys.stdout = open('forwaring.log', 'w')
    # Frpc(port, targethost,targetport).start()
    # Frpc('192.168.1.41',9081, '192.168.1.38',3389).run()
    Frpc('192.168.1.41',9081, '113.133.177.72',7006).run()
